package api

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/gomodule/redigo/redis"
	"github.com/gorilla/websocket"

	"gin-ws-example/pkg/gredis"
)

var upGrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

type Client struct {
	Socket  *websocket.Conn
	Channel string
}

//用于接收websocket消息
func (c *Client) onMessage() {
	defer func() {
		fmt.Println("onMessage faild")
		c.onClose()
	}()
	for {
		//接收消息
		_, message, err := c.Socket.ReadMessage()
		if err != nil {
			c.onClose()
			break
		}
		//将消息写入对应频道
		fmt.Println("Receive message: ", message)
		gredis.Publish(c.Channel, message)
	}
}

//用于推送websocket消息
func (c *Client) onSend() {
	defer func() {
		fmt.Println("onSend faild")
		c.onClose()
	}()
	psc := redis.PubSubConn{Conn: gredis.RedisConn.Get()}
	if err := psc.Subscribe(redis.Args{}.AddFlat(c.Channel)...); err != nil {
		return
	}
	defer psc.Close()
	for {
		//监听对应频道的消息
		switch msg := psc.Receive().(type) {
		case error:
			return
		case redis.Message:
			//将消息推送至客户端
			fmt.Println("Push message: ", msg.Data)
			c.Socket.WriteMessage(websocket.TextMessage, msg.Data)
		case redis.Subscription:
			if msg.Count == 0 {
				return
			}
		}
	}
}

//用于关闭websocket
func (c *Client) onClose() {
	//关闭websocket
	defer c.Socket.Close()
	fmt.Println("ws closed")

	//取消消息订阅
	psc := redis.PubSubConn{Conn: gredis.RedisConn.Get()}
	psc.Unsubscribe(redis.Args{}.AddFlat(c.Channel)...)

}

//webSocket请求
func WsHandler(c *gin.Context) {
	//升级get请求为webSocket协议
	ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		return
	}
	client := &Client{Socket: ws, Channel: "a"}
	fmt.Println("ws on")

	//监听消息队列，推送消息
	fmt.Println("ws onSend")
	go client.onSend()
	//接收消息
	fmt.Println("ws onMessage")
	go client.onMessage()
}
